﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Bamboo.CodeCat
{
    /// <summary>
    /// 去除源代码中的注释
    /// </summary>
    public class CommentRemover
    {
        public List<CommentRemoverItem> Items;

        public void AddDir(string dirname, string pattern, SearchOption option, Encoding e, CommentRemoverLang lang)
        {
            var files = Directory.GetFiles(dirname, pattern, option);
            foreach (var file in files)
            {
                var item = new CommentRemoverItem();
                item.FileName = file;
                item.Encoding = e;
                item.Lang = lang;
                Items.Add(item);
            }
        }

        public void Execute()
        {
            foreach (var item in Items)
            {
                try
                {
                    string input = System.IO.File.ReadAllText(item.FileName, item.Encoding);
                    string output = input;
                    if (item.Lang == CommentRemoverLang.CPP)
                    {
                        output = RemoveCppComment(input);
                    }
                    else
                    {
                        throw new Exception("不支持去除该语言的注释：" + item.Lang);
                    }
                    item.Changed = (input != output);
                    if (item.Changed)
                    {
                        System.IO.File.WriteAllText(item.FileName, output, item.Encoding);
                    }
                }
                catch (Exception ex)
                {
                    item.Error = ex;
                }
               
            }
        }

        public string RemoveCppComment(string input)
        {
            /*
                C++ 注释一般有两种：
                // - 一般用于单行注释。
                /* ... * /一般用于多行注释。
            */
            int status = 0;
            var output = new StringBuilder(input.Length);
            for (int i = 0; i < input.Length; ++i)
            {
                char ch = input[i];
                bool hasNextCh = i < input.Length - 1;
                switch (status)
                {
                    case 0:
                        if (hasNextCh && ch == '/' && input[i + 1] == '/')
                        {
                            status = 100;
                            ++i;
                        }
                        else if (hasNextCh && ch == '/' && input[i + 1] == '*')
                        {
                            status = 200;
                            ++i;
                        }
                        else
                        {
                            output.Append(ch);
                        }
                        break;
                    case 100:
                        if (ch == '\n')
                        {
                            status = 0;
                            output.Append('\n');
                        }
                        else if (hasNextCh && ch == '\r' && input[i+1] == '\n')
                        {
                            status = 0;
                            output.Append("\r\n");
                        }
                        break;
                    case 200:
                        if (hasNextCh && ch == '*' && input[i+1] == '/')
                        {
                            status = 0;
                        }
                        break;
                    default: throw new Exception("该状态程序未做处理：" + status);
                }
            }
            return output.ToString();
        }
    }

    public class CommentRemoverItem
    {
        public string FileName;
        public CommentRemoverLang Lang;
        public Encoding Encoding;
        public Exception Error;
        public bool Changed = false;
        public bool Successful => this.Error == null;
    }

    public enum CommentRemoverLang
    {
        NONE = 0,
        CPP = 1,
        JAVA =2,
        DOTNET = 3
    }
}
